Step FunctionsステートマシンからDynamoDBテーブル上の複数のアイテムをUpdateItemしたい(AWS CDK)
こんにちは、CX事業本部 IoT事業部の若槻です。
今回は、Step FunctionsステートマシンからDynamoDBテーブル上の複数のアイテムをUpdateItemする方法を確認し、AWS CDKで実装してみました。
PutItemとUpdateItemの違い
本題に入る前に、まずDynamoDBのPutItemとUpdateItemの違いについて確認します。
PutItemとUpdateItemは、どちらもDynamoDBテーブル上のアイテムを1つ更新するAPI操作ですが、その更新時の違いは以下のようになります。
説明 | |
---|---|
PutItem | 入力で指定したアイテムで、既存のアイテムを置き換える。 |
UpdateItem | 入力で指定した属性情報で、既存のアイテムの属性情報を更新する。 |
例えばDynamoDBテーブルに下記の既存アイテムがあるとします。deviceId
がPartition Keyです。
//既存アイテム { "deviceId": "d001", "deviceName": "デバイス001", "temperature": 25 }
この時以下の入力を指定して、PutItemを行った場合とUpdateItemを行った場合だと、
//入力 { "deviceId": "d001", "temperature": 8 }
アイテムの更新結果はそれぞれ以下のようになります。PutItemは入力で指定されていない属性は削除されますが、UpdateItemは残されます。
//PutItemの結果 { "deviceId": "d001", "temperature": 8 } //UpdateItemの結果 { "deviceId": "d001", "deviceName": "デバイス001", "temperature": 8 }
またいずれのAPI操作も既定では指定のキーのアイテムが存在しない場合はアイテム新規作成が行われます。
BatchWriteItemではUpdateItemができない
一方で、BatchWriteItemはDynamoDBテーブル上のアイテムを複数更新する操作ですが、行える更新操作はPutItemまたはDeleteItemのみです。UpdateItemは行なえません。
ドキュメントにも代わりにUpdateItemを直接使用するように書いてあります。
BatchWriteItem cannot update items. To update items, use the UpdateItem action.
Step FunctionsステートマシンからDynamoDBテーブル上の複数のアイテムをUpdateItemしたい
以上を踏まえると、Step FunctionsステートマシンからDynamoDBテーブル上の複数のアイテムをUpdateItemしたい場合、以下の方法が考えられます。
- MapステートでUpdateItemを使用する
- TransactWriteItemsを使用する
TransactWriteItemsではPutItem、UpdateItemまたはDeleteItemの更新操作が可能で、25個までのアイテムであれば一度のAPI操作で更新が可能です。また状態遷移の回数も一度で済みます。そこで今回はTransactWriteItemsで複数アイテムのUpdateを行ってみます。
やってみた
CDKコード
AWS CDKで実装します。DynamoDBテーブルとステートマシンを下記の通り定義します。
import * as cdk from '@aws-cdk/core'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import * as tasks from '@aws-cdk/aws-stepfunctions-tasks'; import * as dynamodb from '@aws-cdk/aws-dynamodb'; export class AwsCdkAppStack extends cdk.Stack { constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const deviceTable = new dynamodb.Table(this, 'deviceTable', { tableName: 'deviceTable', partitionKey: { name: 'deviceId', type: dynamodb.AttributeType.STRING }, billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, }); const updateDeviceData = new tasks.CallAwsService( this, 'updateDeviceData', { service: 'dynamodb', action: 'transactWriteItems', parameters: { 'TransactItems.$': '$.TransactItems', }, iamResources: [deviceTable.tableArn], iamAction: 'dynamodb:*', } ); new sfn.StateMachine(this, 'updateDeviceDataStateMachine', { stateMachineName: 'updateDeviceDataStateMachine', definition: updateDeviceData, }); } }
cdk deploy
でデプロイします。
動作
準備としてDynamoDBテーブルに以下のようにデータを作成しておきます。
以下のJsonを入力としてステートマシンを実行してみます。
{ "TransactItems": [ { "Update": { "TableName": "deviceTable", "Key": { "deviceId": { "S": "d001" } }, "ExpressionAttributeValues": { ":temperature": { "N": "10" } }, "ExpressionAttributeNames": { "#temperature": "temperature" }, "UpdateExpression": "SET #temperature = :temperature" } }, { "Update": { "TableName": "deviceTable", "Key": { "deviceId": { "S": "d003" } }, "ExpressionAttributeValues": { ":temperature": { "N": "15" }, ":deviceName": { "S": "デバイス003" } }, "ExpressionAttributeNames": { "#deviceName": "deviceName", "#temperature": "temperature" }, "UpdateExpression": "SET #deviceName = :deviceName, #temperature = :temperature" } } ] }
ステートマシンの実行が成功しました。
テーブル上のデータが指定通りに更新されています。
参考
- DynamoDBのputItemとupdateItemの違い | ハックノート
- UpdateItem - Amazon DynamoDB
- PutItem - Amazon DynamoDB
- TransactWriteItems - Amazon DynamoDB
以上